package fr.insalyon.sims.broadcast.tools;

import java.awt.image.BufferedImage;
import fr.insalyon.sims.SIMSImageUtils;
import fr.insalyon.sims.broadcast.network.DataEvent;
import fr.insalyon.sims.broadcast.network.DataListener;

public class ImageBuilder implements DataListener {
	// ------------------------------------------------------- CONSTANTS -- //
	
	private final static int READ_HEADER = 1, READ_RAW_DATA = 2;
	
	private final static int HEADER_SIZE = 24;
	
	// ------------------------------------------------------ ATTRIBUTES -- //
	
	private int status;
	
	private int dataOffset;
	
	private byte[] header;
	
	private byte[] rawData;
	
	private Object lock;
	
	private BufferedImage lastImage;
	
	// ---------------------------------------------------- CONSTRUCTORS -- //
	
	public ImageBuilder() {
		this.status = READ_HEADER;
		this.lock = new Object();
	}
	
	// --------------------------------------------------------- METHODS -- //
	
	public synchronized void dataReceived(DataEvent event) {
		byte[] data = event.getData();
		
		switch (status) {
		case READ_HEADER:
			System.out.println(event.getLength());
			
			// Read image header
			header = new byte[HEADER_SIZE];
			System.arraycopy(data, event.getOffset(), header, 0, HEADER_SIZE);
			
			int imageSize = SIMSImageUtils.getSizeFromByteArray(header);
			rawData = new byte[imageSize];
			System.arraycopy(data, event.getOffset() + HEADER_SIZE, rawData, 0,
					event.getLength() - HEADER_SIZE);
			
			System.out.println("size: " + imageSize);
			
			dataOffset = event.getLength() - HEADER_SIZE;
			status = READ_RAW_DATA;
			break;
		case READ_RAW_DATA:
			// Read image raw data
			int rawDataLength = Math.min(
					event.getLength(), rawData.length - dataOffset);
			
			System.arraycopy(data, event.getOffset(),
					rawData, dataOffset, rawDataLength);
			dataOffset += rawDataLength;
			
			System.out.println(dataOffset + " " + rawData.length);
			
			if (dataOffset == rawData.length) {
				try {
					System.out.println("full image #" + SIMSImageUtils.getRankFromByteArray(header));
					lastImage = SIMSImageUtils.getBufferedImageFromByteArray(
							header, rawData);
				} catch (Exception e) {
					lastImage = null;
					e.printStackTrace();
				}
				synchronized (lock) {
					lock.notifyAll();
				}
				status = READ_HEADER;
			}
			
			if (rawDataLength != event.getLength())
				dataReceived(new DataEvent(
						event.getSource(), data,
						event.getOffset() + rawDataLength,
						event.getLength() - rawDataLength));
			break;
		}
	}
	
	public BufferedImage retrieveImage() {
		synchronized (lock) {
			try {
				lock.wait();
			} catch (InterruptedException e) {
				// Ignored
			}
		}
		
		return lastImage;
	}
	
	// ------------------------------------------------- PRIVATE METHODS -- //
	// --------------------------------------------------- INNER CLASSES -- //
}
